<html xmlns="http://www.w3.org/1999/xhtml" id="rpc-soap">
<head>
    <title>SOAP</title>
</head>

<body>
<warning>
This feature works in proxied applications only.  It does not work in SOLO applications.
</warning>
<h1>SOAP</h1>

<p>SOAP (Simple Object Access Prototcol) is used to exchange information in a
distributed environment. A typical scenario involves a SOAP client invoking a
client-side function stub to invoke a SOAP web service operation. The SOAP web
service then returns data &#8212;such as stock information or the result to
a math function&#8212; to the client. The <a href="http://www.w3.org/TR/soap/">SOAP protocol</a> is a
work in progress being drafted by the <a href="http://www.w3.org">W3C</a>.</p>

<p>This chapter discusses how to use and invoke SOAP web services in an LZX
application. OpenLaszlo SOAP is part of OpenLaszlo RPC and shares many of the same APIs
and concepts. This chapter assumes that you have read the OpenLaszlo RPC chapter
and have a basic knowledge of SOAP, WSDL, XML, namespaces, and XML Schema. WSDL
(Web Service Definition Language) is an XML format to describe a web service. A
WSDL may also describe the types used by a web service using an XML Schema. XML
Schema defines the structure and constraints of XML documents. For more information,
see the references section at end of this chapter.</p>

<!-- ============================================================ -->
<!-- soap                                                         -->
<!-- ============================================================ -->
<h2>&lt;soap&gt;</h2>

<p>The <tagname link="true">soap</tagname> element creates a client-side representation of a SOAP
service based on a WSDL. The name and wsdl attributes are required.</p>

<example title="A simple SOAP tag" extract="false">
&lt;soap wsdl="..."
      service="..."
      port="..."
      autoload="[true|false]"
      secure="[true|false]"
      secureport="..." &gt;
</example>

<!-- ============================================================ -->
<!-- attributes/methods                                           -->
<!-- ============================================================ -->
<h3><tagname>soap</tagname> attributes</h3>
<p>The <tagname>soap</tagname> element accepts the following attributes, some of which are required:</p>

<p><dfn>wsdl</dfn>: (String) the WSDL to use for the SOAP object. File or http
URLs may be used, such as <tt>file:mylocal.wsdl</tt> or
<tt>http://api.google.com/GoogleSearch.wsdl</tt>. <b>This is a required
attribute.</b></p>

<p><dfn>service</dfn>: (String) set this value to the desired SOAP service if
more than one SOAP service is available. <b>Default is the first SOAP
service.</b> After the soap object loads, the service property is set with the
name of the SOAP service being used.</p>

<p><dfn>port</dfn>: (String) set this value if more than one SOAP port is
available. <b>Default is the first SOAP port.</b> Once the soap object loads,
the service property is set with the name of the SOAP port being used.</p>

<p><dfn>requestheaders</dfn>: (String) set this value to set SOAP request
headers. The string must contain XML and multiple nodes are allowed, i.e., a
root node is not required. See the "SOAP headers" section for more
details. <b>Default is null.</b></p>

<p><dfn>responseheaders</dfn>: (LzDataset) if this is set, the responseheaders
dataset contains the response header information from the last call that
returned headers. See the "SOAP headers" section below for more
details. <b>Default is null.</b></p>

<p><dfn>autoload</dfn>: (Boolean) if true, calls to load client proxy during
init stage. If false, the proxy must be loaded using the load() method. See the
proxy section in the RPC chapter for details. <b>Default is true.</b></p>

<p><dfn>secure</dfn>: (Boolean) if true, creates a secure HTTPS connection
between the client and OpenLaszlo Server. Also see secureport below. <b>Default is
false.</b></p>

<p><dfn>secureport</dfn>: (Number) valid only when secure attribute is set to
true. The secure port to use. There is no client-side default. Most servers use
port 443 as the default HTTPS port.</p>


<h3>Read-only properties</h3>

<p><dfn>proto</dfn>: (Object) contains prototypes that can be used to create
objects described in the types section of a WSDL. These prototypes can be used
to instantiate parameter objects to pass SOAP rpc-style functions. Returned
objects from a SOAP call will also be prototyped. The prototypes are mapped to
&lt;complexType&gt; elements found in a WSDL's schema. See the "Passing complex
type parameters" section for more details.</p>

<p><dfn>proxy</dfn>: (Object) this is the object containing function stubs. It
is created by calling load() (which happens during init if <attribute>autoload</attribute> is
true). The proxy functions are stubs to SOAP operations defined by the
WSDL. 
</p>
<p>Note that <code>proxy</code> is not defined until the <code>onload </code>event is sent, thus
function stubs cannot be invoked until <code>onload.</code> Each function stub requires two
arguments: an array of parameters and delegate. You can unload it (i.e., set to
null) by calling the <method>unload()</method> method. Go to the proxy section in the RPC chapter
for details.</p>


<h3>Events</h3>

<p>Note: event handler methods must be declared in the body of &lt;soap&gt;.
Attribute event handlers will not work.</p>

<p><dfn>onload</dfn>: this event is triggered when the proxy is returned
to the client.</p>

<p><dfn>onunload</dfn>: this event is triggered when the proxy is unloaded from
the client.</p>

<p><dfn>ondata</dfn>: this event is triggered when a declared &lt;remotecall&gt;
doesn't handle its ondata events. See the &lt;remotecall&gt; section for
details.</p>

<p><dfn>onerror</dfn>: this event is triggered if there was a problem loading or
unloading the stub, or if a declared &lt;remotecall&gt; didn't handle its
onerror event. See the &lt;remotecall&gt; section for details.</p>


<h3>Methods</h3>

<h4><a name="load">load()</a></h4>

<p>Load() is responsible for setting up the proxy property. This method is
automatically invoked if autoload is true. When the call returns, an onload
event is sent and the proxy will contain function stubs that mirror the SOAP
operations defined in the WSDL.</p>
<p>
Here's an example that shows a Laszlo application interacting with the SOAP service provided by 
Amazon.com.  This example doesn't do much: it merely shows that the two ends are communicating.
</p>

<example title="Loading Amazon SOAP service">
&lt;canvas debug="true" height="530"&gt;

    &lt;debug x="15" y="15" width="415" height="500" /&gt;

    &lt;soap name="amazon" wsdl="http://soap.amazon.com/schemas3/AmazonWebServices.wsdl"&gt;

        &lt;method event="onload"&gt;
            Debug.write('Amazon soap service loaded');
            Debug.write('Compare proxy stubs with WSDL SOAP operations.');
            Debug.write('Amazon WSDL at ' + this.wsdl);            
            Debug.write('proxy:');
            Debug.inspect(this.proxy);
        &lt;/method&gt;

        &lt;method event="onerror" args="error"&gt;
            debug.write('error:', error);
        &lt;/method&gt;

    &lt;/soap&gt;

&lt;/canvas&gt;
</example>

<h4>unload()</h4>

<p>This method unloads the proxy from the RPC object and sets it to null. When
the call returns, an onunload event is sent.</p>
<p>
In the example below, the, SOAP service is unloaded.
</p>

<example title="Unloading Amazon SOAP service">
&lt;canvas debug="true" height="170"&gt;

    &lt;debug x="10" y="10" width="415" height="150" /&gt;

    &lt;soap name="amazon" wsdl="http://soap.amazon.com/schemas3/AmazonWebServices.wsdl"&gt;

        &lt;method event="onload"&gt;
            Debug.write('Amazon soap service loaded');
            Debug.write('proxy is:', this.proxy);
            this.unload();
        &lt;/method&gt;

        &lt;method event="onunload"&gt;
            Debug.write('Amazon soap service unloaded');
            Debug.write('proxy is:', this.proxy)
        &lt;/method&gt;

        &lt;method event="onerror" args="error"&gt;
            debug.write('error:', error);
        &lt;/method&gt;

    &lt;/soap&gt;

&lt;/canvas&gt;
</example>

<h2>Document style operation</h2>

<p>Document style operations use XML data(that is, documents) as paramaters. The SOAP
specification is moving towards document style operations as being the preferred
way of invoking web services. The alternative RPC style posed interoperability
challenges that were difficult to resolve. The WS-I's <a
href="http://www.ws-i.org/archive/Profiles/Basic/2002-10/basicprofile-1.0-wgd.htm">Basic
Profile 1.0 Draft</a> describes a preference to document style, which is also
the preferred style in SOAP 1.2.</p>

<example title="WS-I Basic Profile 1.0 Draft: Section 4.1, R1005-R1007" extract="false">
R1005 MESSAGEs MUST NOT contain soap:encodingStyle attributes on any of the
elements whose [namespace name] is "http://schemas.xmlsoap.org/soap/envelope/".

R1006 MESSAGEs MUST NOT contain soap:encodingStyle attributes on any element
which is a child of soap:Body.

R1007 MESSAGEs MUST NOT contain soap:encodingStyle attributes on any elements
which are grandchildren of soap:Body.

For interoperability, literal XML is preferred.
</example>

<p>In the application, a document style operation returns an array of
<tagname link="true">LzDataElement</tagname>s, though often only a single
<tagname>LzDataElement</tagname> will exist in the array.</p>

<p>The parameter passed into the operation must match the XML schema as defined
in the WSDL. The parameter passed in can be an XML string or a dataset. The
following example demonstrates how to invoke a document style operation through
LZX.</p>

<example title="Document style SOAP operation">
&lt;canvas debug="true"&gt;

    &lt;debug y="30" x="145" width="350" height="300" /&gt;

    &lt;!-- This SOAP service uses document/literal messages for its
         operations. Each operation is passed a document as a parameter. --&gt;
    &lt;soap name="maths" 
          wsdl="http://www.dotnetjunkies.com/quickstart/aspplus/samples/services/MathService/VB/MathService.asmx?WSDL"&gt;

        &lt;!-- Method to make a document for SOAP message requests --&gt;
        &lt;method name="makedoc" args="func, av, bv"&gt;
        &lt;![CDATA[
            if (func == null) return;
            var s =  '&lt;' + func + ' xmlns="' + 'http://tempuri.org/' + '" &gt;' + 
                               '&lt;A&gt;' + av + '&lt;/A&gt;' + 
                               '&lt;B&gt;' + bv + '&lt;/B&gt;' + 
                   '&lt;/' + func + '&gt;';
            debug.write(s);
            return s;
        ]]&gt;
        &lt;/method&gt;
       
        &lt;method event="onload"&gt;
            // make buttons visible once SOAP object is loaded
            canvas.buttons.setAttribute('visible', true);            
        &lt;/method&gt;

        &lt;method event="onerror" args="error"&gt;
            debug.write('error:', error);
        &lt;/method&gt;

        &lt;method event="ontimeout" args="error"&gt;
            debug.write('timeout:', error);
        &lt;/method&gt;

        &lt;method event="ondata" args="value"&gt;
            debug.write(value);
            result.setText(value);
        &lt;/method&gt;

        &lt;remotecall funcname="Add"&gt;
            &lt;param value="${ canvas.maths.makedoc(parent.name, a.text, b.text) }" /&gt;
        &lt;/remotecall&gt;
        &lt;remotecall funcname="Subtract"&gt;
            &lt;param value="${ canvas.maths.makedoc(parent.name, a.text, b.text) }" /&gt;
        &lt;/remotecall&gt;
        &lt;remotecall funcname="Multiply"&gt;
            &lt;param value="${ canvas.maths.makedoc(parent.name, a.text, b.text) }" /&gt;
        &lt;/remotecall&gt;
        &lt;remotecall funcname="Divide"&gt;
            &lt;param value="${ canvas.maths.makedoc(parent.name, a.text, b.text) }" /&gt;
        &lt;/remotecall&gt;
    &lt;/soap&gt;

    &lt;view name="buttons" x="10" y="10" visible="false" layout="spacing: 10" &gt;
        &lt;text&gt;&lt;b&gt;.NET MathService&lt;/b&gt;&lt;/text&gt;

        &lt;view layout="axis: x" &gt;&lt;text y="3"&gt;a:&lt;/text&gt;&lt;edittext id="a" text="10"/&gt;&lt;/view&gt;
        &lt;view layout="axis: x" &gt;&lt;text y="3"&gt;b:&lt;/text&gt;&lt;edittext id="b" text="2" /&gt;&lt;/view&gt;
        &lt;view layout="axis: x" &gt;&lt;text&gt;result:&lt;/text&gt;&lt;text id="result"/&gt;&lt;/view&gt;

        &lt;button text="add"      onclick="canvas.maths.Add.invoke()" /&gt;
        &lt;button text="subtract" onclick="canvas.maths.Subtract.invoke()" /&gt;
        &lt;button text="multiply" onclick="canvas.maths.Multiply.invoke()" /&gt;
        &lt;button text="divide"   onclick="canvas.maths.Divide.invoke()" /&gt;

    &lt;/view&gt;

&lt;/canvas&gt;
</example>

<p>The XML Schema in the WSDL describes how the XML should be structured for
each of the operations. The WSDL below describes how what the schema should look
like for the Add operation.</p>

<example title="XML Schema for .NET Math" extract="false">
&lt;definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns:s="http://www.w3.org/2001/XMLSchema"
             xmlns:s0="http://tempuri.org/"
             xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
             xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
             xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
             targetNamespace="http://tempuri.org/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"&gt;

  &lt;types&gt;
    &lt;s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/"&gt;
      &lt;s:element name="Add"&gt;
        &lt;s:complexType&gt;
          &lt;s:sequence&gt;
            &lt;s:element minOccurs="1" maxOccurs="1" name="A" type="s:float" /&gt;
            &lt;s:element minOccurs="1" maxOccurs="1" name="B" type="s:float" /&gt;
          &lt;/s:sequence&gt;
        &lt;/s:complexType&gt;
      &lt;/s:element&gt;

      &lt;s:element name="AddResponse"&gt;
        &lt;s:complexType&gt;
          &lt;s:sequence&gt;
            &lt;s:element minOccurs="1" maxOccurs="1" name="AddResult" type="s:float" /&gt;
          &lt;/s:sequence&gt;
        &lt;/s:complexType&gt;
      &lt;/s:element&gt;

      &lt;!-- MORE SCHEMA DECLARATION (for Subtract, Multiply, Divide) HERE --&gt;

    &lt;/s:schema&gt;
  &lt;/types&gt;

  &lt;message name="AddSoapIn"&gt;
    &lt;part name="parameters" element="s0:Add" /&gt;
  &lt;/message&gt;
  &lt;message name="AddSoapOut"&gt;
    &lt;part name="parameters" element="s0:AddResponse" /&gt;
  &lt;/message&gt;

  &lt;!-- OTHER MESSAGES (for Subtract, Multiply, Divide) HERE --&gt;

  &lt;portType name="MathServiceSoap"&gt;
    &lt;operation name="Add"&gt;
      &lt;input message="s0:AddSoapIn" /&gt;
      &lt;output message="s0:AddSoapOut" /&gt;
    &lt;/operation&gt;
    &lt;!-- OTHER PORT TYPE OPERATIONS (for Subtract, Multiply, Divide) HERE --&gt;
  &lt;/portType&gt;

  &lt;binding name="MathServiceSoap" type="s0:MathServiceSoap"&gt;
    &lt;soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /&gt;
    &lt;operation name="Add"&gt;
      &lt;soap:operation soapAction="http://tempuri.org/Add" style="document" /&gt;
      &lt;input&gt;
        &lt;soap:body use="literal" /&gt;
      &lt;/input&gt;
      &lt;output&gt;
        &lt;soap:body use="literal" /&gt;
      &lt;/output&gt;
    &lt;/operation&gt;
    &lt;!-- OTHER SOAP BINDING OPERATIONS (for Subtract, Multiply, Divide) HERE --&gt;
  &lt;/binding&gt;

  &lt;service name="MathService"&gt;
    &lt;port name="MathServiceSoap" binding="s0:MathServiceSoap"&gt;
      &lt;soap:address location="http://www.dotnetjunkies.com/quickstart/aspplus/samples/services/MathService/VB/MathService.asmx" /&gt;
    &lt;/port&gt;
  &lt;/service&gt;

&lt;/definitions&gt;
</example>

<p>The WSDL describes that Add is a document style operation and that a single
element (XML message) is passed in. According to the XML schema, the XML message
for the Add operation has to look something like:</p>

<example extract="false">
&lt;Add xmlns="http://tempuri.org/"&gt;
  &lt;A&gt;NUMBER&lt;/A&gt;
  &lt;B&gt;NUMBER&lt;/B&gt;
&lt;/Add&gt;
</example>

<p>Notice that the XML Schema describes elements that are in the
"http://tempuri.org/". When creating the XML, make sure namespaces and elements
match exactly as described in the schema. For example, "http://tempuri.org/"
(trailing slash) and "http://tempuri.org" (no trailing slash) are not the same
namespace. The schema describes that the Add element contains elements
&lt;A&gt;NUMBER&lt;/A&gt; and &lt;B&gt;NUMBER&lt;/B&gt;. Since the case of each
element name matters, it would be wrong to declare &lt;a&gt;number&lt;/a&gt; and
&lt;b&gt;number&lt;/b&gt; in the Add element.</p>


<h2>RPC style operation</h2>

<p>RPC style operations behave just like functions in that, instead of
documents, values are passed in as parameters. Parameters can be of simple data
type (number, boolean), array, or object. The parameter type for the operation
is described in the WSDL's XML schema.</p>

<example title="Passing simple paramaters in RPC style operation">
&lt;canvas debug="true" height="400" width="530"&gt;

    &lt;debug x="10" y="190" width="510" height="200" /&gt;

    &lt;dataset name="googleDset" /&gt;

    &lt;soap name="google" wsdl="http://api.google.com/GoogleSearch.wsdl"&gt;
        &lt;method event="onload"&gt;
            Debug.write('google soap service loaded');
        &lt;/method&gt;

        &lt;method event="onerror" args="error"&gt;
            debug.write('error:', error);
        &lt;/method&gt;

        &lt;!-- See RPC chapter for details on remotecall and how dataobject is
             used to data bind to RPC operation results. --&gt; 
        &lt;remotecall name="search" funcname="doGoogleSearch" 
                    dataobject="googleDset"&gt;

            &lt;param value="'2TKUw4ZQFHJ84ByemZK0EXV0Lj+7xGOx'" /&gt;
            &lt;param value="${ s.text }" /&gt;
            &lt;param value="1" /&gt;
            &lt;param value="10" /&gt;
            &lt;param value="true" /&gt;
            &lt;param value="''" /&gt;
            &lt;param value="true" /&gt;
            &lt;param value="''" /&gt;
            &lt;param value="''" /&gt;
            &lt;param value="''" /&gt;

            &lt;method event="ondata" args="value"&gt;
                debug.write('search result:\n', value);
            &lt;/method&gt;

        &lt;/remotecall&gt;
    &lt;/soap&gt;

    &lt;view x="10" y="10" layout="spacing: 5" &gt;
        &lt;view layout="axis: x; spacing: 5"&gt;
            &lt;edittext id="s" text="SOAP" /&gt;
            &lt;button text="search" onclick="Debug.write('Invoking search...'); google.search.invoke()" /&gt;
        &lt;/view&gt;

        &lt;view width="505" height="140" bgcolor="silver" clip="true" layout="axis: y" &gt;
            &lt;view&gt;
                &lt;datapath xpath="googleDset:/resultElements/item" pooling="true" /&gt;
                &lt;text width="200" datapath="title/text()" clip="true" /&gt;
                &lt;text x="205" width="300" datapath="URL/text()" clip="true" /&gt;
            &lt;/view&gt;
        &lt;/view&gt;

    &lt;/view&gt;

&lt;/canvas&gt;
</example>

<p>The example demonstrates how a result value, which is actually a JavaScript
object, can be data bound through the dataobject attribute in remotecall. For
more details, see the remotecall section in the RPC chapter.</p>

<h3>Passing complex type parameters</h3>

<p>There are RPC style operations that require complex type parameters which are
described in the WSDL's XML schema. For instance, the Amazon WSDL has a SOAP
operation called KeywordSearchRequest that expects a KeywordRequest type
parameter.</p>

<example title="Amazon WSDL: KeywordSearchRequest SOAP operation" extract="false">
&lt;!-- For complete WSDL go to
        http://soap.amazon.com/schemas3/AmazonWebServices.wsdl --&gt;

&lt;wsdl:definitions name="AmazonSearch"
                  xmlns:typens="http://soap.amazon.com"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns="http://schemas.xmlsoap.org/wsdl/"
                  targetNamespace="http://soap.amazon.com"&gt;

  &lt;wsdl:types&gt;

    &lt;xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                targetNamespace="http://soap.amazon.com"&gt;

      &lt;xsd:complexType name="KeywordRequest"&gt;
        &lt;xsd:all&gt;
          &lt;xsd:element name="keyword" type="xsd:string"/&gt;
          &lt;xsd:element name="page" type="xsd:string"/&gt;
          &lt;xsd:element name="mode" type="xsd:string"/&gt;
          &lt;xsd:element name="tag" type="xsd:string"/&gt;
          &lt;xsd:element name="type" type="xsd:string"/&gt;
          &lt;xsd:element name="devtag" type="xsd:string"/&gt;
          &lt;xsd:element name="sort" type="xsd:string" minOccurs="0"/&gt;
          &lt;xsd:element name="locale" type="xsd:string" minOccurs="0"/&gt;
          &lt;xsd:element name="price" type="xsd:string" minOccurs="0"/&gt;
        &lt;/xsd:all&gt;
      &lt;/xsd:complexType&gt;

      &lt;xsd:complexType name="ProductInfo"&gt;

        &lt;xsd:all&gt;
          &lt;xsd:element name="TotalResults" type="xsd:string" minOccurs="0"/&gt;
          &lt;!-- Total number of Search Results --&gt;
          &lt;xsd:element name="TotalPages" type="xsd:string" minOccurs="0"/&gt;
          &lt;!-- Total number of Pages of Search Results --&gt;
          &lt;xsd:element name="ListName" type="xsd:string" minOccurs="0"/&gt;
          &lt;!-- Listmania list name --&gt;
          &lt;xsd:element name="Details" type="typens:DetailsArray" minOccurs="0"/&gt;
        &lt;/xsd:all&gt;

      &lt;/xsd:complexType&gt;

      &lt;!-- OTHER SCHEMA TYPES HERE --&gt;

    &lt;/xsd:schema&gt;

  &lt;/wsdl:types&gt;

  &lt;message name="KeywordSearchRequest"&gt;
    &lt;!-- Messages for Amazon Web APIs --&gt;
    &lt;!-- KeywordSearchRequest message contains only one part and is of type
         typens:KeywordRequest --&gt;
    &lt;part name="KeywordSearchRequest" type="typens:KeywordRequest"/&gt;
  &lt;/message&gt;

  &lt;message name="KeywordSearchResponse"&gt;
    &lt;part name="return" type="typens:ProductInfo"/&gt;
  &lt;/message&gt;

  &lt;portType name="AmazonSearchPort"&gt;
    &lt;!-- Port for Amazon Web APIs --&gt;
    &lt;operation name="KeywordSearchRequest"&gt;
      &lt;!-- The KeywordSearchRequest message element (above) describes input. --&gt;
      &lt;input message="typens:KeywordSearchRequest"/&gt;
      &lt;!-- The KeywordSearchResponse message element (above) describes
           input. --&gt;
      &lt;output message="typens:KeywordSearchResponse"/&gt;
    &lt;/operation&gt;

    &lt;!-- OTHER OPERATIONS HERE --&gt;

  &lt;/portType&gt;

  &lt;binding name="AmazonSearchBinding" type="typens:AmazonSearchPort"&gt;

    &lt;soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/&gt;

    &lt;!-- Binding for Amazon Web APIs - RPC, SOAP over HTTP --&gt;
    &lt;!-- This binds to the AmazonSearchPort portType operation above. --&gt; 
    &lt;operation name="KeywordSearchRequest"&gt;

      &lt;soap:operation soapAction="http://soap.amazon.com"/&gt;

      &lt;input&gt;
        &lt;soap:body use="encoded" 
                   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                   namespace="http://soap.amazon.com"/&gt;
      &lt;/input&gt;
      &lt;output&gt;
        &lt;soap:body use="encoded" 
                   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                   namespace="http://soap.amazon.com"/&gt;
      &lt;/output&gt;

    &lt;/operation&gt;

    &lt;!-- OTHER OPERATIONS HERE --&gt;

  &lt;/binding&gt;

  &lt;service name="AmazonSearchService"&gt;

    &lt;port name="AmazonSearchPort" binding="typens:AmazonSearchBinding"&gt;

      &lt;soap:address location="http://soap.amazon.com/onca/soap3"/&gt;

    &lt;/port&gt;

  &lt;/service&gt;

&lt;/wsdl:definitions&gt;
</example>

<p>The <dfn>proto</dfn> property in a soap object can be used to pass complex
types as parameters. When the soap object loads, its proto property is set with
JavaScript function prototypes representing complex structures described in the
WSDL. In Amazon WSDL, the KeywordSearchRequest operation expects a
KeywordRequest parameter. To invoke KeywordSearchRequest, the proto property
should be used to instantiate a KeywordRequest object as shown in this
example.</p>

<example title="Invoking a SOAP operation using a complex type value">
&lt;canvas debug="true" height="530"&gt;

    &lt;debug x="10" y="40" width="470" height="450" /&gt;

    &lt;soap name="amazon" wsdl="http://soap.amazon.com/schemas3/AmazonWebServices.wsdl"&gt;

        &lt;attribute name="handlerDel" value="null" type="expression" /&gt;

        &lt;method event="onload"&gt;
            Debug.write('Amazon soap service loaded.');
            Debug.write('Click keyword search button to get started.');
            Debug.write('--');
            search.setAttribute('visible', true);            
        &lt;/method&gt;

        &lt;method event="onerror" args="error"&gt;
            debug.write('error:', error);
        &lt;/method&gt;

        &lt;method name="invokeKeywordSearchRequest" args="keyword"&gt;

            //------------------------------------------------------------
            // Instantiate proto.KeywordRequest prototype to pass into
            // KeywordSearchRequest.
            //------------------------------------------------------------
            var keyReqParam = new this.proto.KeywordRequest();

            keyReqParam.keyword = keyword;
            keyReqParam.page = 1;
            keyReqParam.mode = 'book';
            keyReqParam.tag = 'webservices-20';
            keyReqParam.type = 'lite';
            keyReqParam.devtag = 'your-dev-tag';
            keyReqParam.format = 'xml';
            keyReqParam.version = '1.0';

            if (this.handlerDel == null) {
                this.handlerDel = new LzDelegate(this, 'handler');
            }

            //------------------------------------------------------------
            // Array of parameters and a delegate for callback handler must
            // be passed in when invoking raw stub function.  For more
            // information on proxy, see proxy section in RPC chapter
            //------------------------------------------------------------
            Debug.write('Invoking Amazon KeywordSearchRequest...');

            this.proxy.KeywordSearchRequest( [ keyReqParam ], this.handlerDel);
        &lt;/method&gt;

        &lt;method name="handler" args="response"&gt;
            Debug.write('Got response:', response);
        &lt;/method&gt;

    &lt;/soap&gt;

    &lt;view id="search" x="10" y="10" layout="spacing: 5" visible="false"&gt;
        &lt;view layout="axis: x; spacing: 5"&gt;
            &lt;edittext id="s" text="services" /&gt;
            &lt;button text="keyword search" onclick="amazon.invokeKeywordSearchRequest(s.text)" /&gt;
        &lt;/view&gt;
    &lt;/view&gt;

&lt;/canvas&gt;
</example>

<p>There are two kinds of prototypes: objects and arrays. An object prototype
contains three properties:</p>

<ul>
    <li><dfn>name</dfn>: (String) type name.</li>
    <li><dfn>ns</dfn>: (LzNamespace) prototype container which is associated to
    a particular namespace. This object is the same object pointed by
    LzNamespace.ns[MYNAMESPACE]. Inspect LzNamespace.ns in the debugger for
    details. The source for LzNamespace can be found in
    lps/components/rpc/library/namespace.js.</li>
    <li><dfn>members</dfn>: (Object) members this prototype contains as
    described in the WSDL.</li>
</ul>

<p>The members property gives the developer an idea of what values should be set
in the object. In the Amazon example, each member in the instantiated
KeywordRequest object can be seen in the members property of the KeywordRequest
prototype. Objects are represented in the WSDL's XML schema like:</p>

<example extract="false">
&lt;!-- Assume xsd is "http://www.w3.org/2001/XMLSchema" and
     soapenc is "http://schemas.xmlsoap.org/soap/encoding/". --&gt;
&lt;xsd:complexType name="COMPLEX_TYPE_NAME"&gt;
  &lt;xsd:all&gt;
    &lt;xsd:element name="NAME1" type="TYPE1" /&gt;
    &lt;xsd:element name="NAME2" type="TYPE2" /&gt;
    &lt;!-- other elements... --&gt;
  &lt;/xsd:all&gt;
&lt;/xsd:complexType&gt;
</example>

<p>An array prototype contains three properties:</p>

<ul>
    <li><dfn>name</dfn>: (String) type name.</li>
    <li><dfn>ns</dfn>: (LzNamespace) prototype container which is associated to
    a particular namespace. This object is the same object pointed by
    LzNamespace.ns[MYNAMESPACE]. Inspect LzNamespace.ns in the debugger for
    details. The source for LzNamespace can be found in
    lps/components/rpc/library/namespace.js.</li>
    <li><dfn>arraytype</dfn>: (QName) type of array this prototype represents,
    as described in the WSDL. A Qname contains a namespace and a localname, both
    of type string. The source for QName can be found in
    lps/components/rpc/library/qname.js.</li>
</ul>
<p>Basic &lt;complexType&gt; and arrays are prototyped in the client based
    on a WSDL's schema. The prototypes are stored in LzNamespace.ns[NAMESPACE],
    where NAMESPACE is the namespace of the schema.</p>
<p>The OpenLaszlo SOAP WSDL parser expects the XML schema array pattern to look like:</p>

<example title="XML schema array pattern" extract="false">
&lt;xsd:complexType name="ARRAY_NAME"&gt;
    &lt;xsd:complexContent&gt;
          &lt;xsd:restriction base="soapenc:Array"&gt;
             &lt;xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="ARRAY_TYPE[]"/&gt;
          &lt;/xsd:restriction&gt;
    &lt;/xsd:complexContent&gt;
&lt;/xsd:complexType&gt;
</example>

<p>The following example demonstrates what the client-side prototype of the
Google XML schema type looks like:</p>

<example title="Google array complex type and object complex type">
&lt;canvas debug="true" height="580" width="530"&gt;

    &lt;debug x="10" y="10" width="510" height="560" /&gt;

    &lt;dataset name="googleDset" /&gt;

    &lt;soap name="google" wsdl="http://api.google.com/GoogleSearch.wsdl"&gt;
        &lt;method event="onload"&gt;
            Debug.write('google soap service loaded');
            Debug.write('----------------');
            Debug.write('google proto:');
            Debug.inspect(google.proto)
            Debug.write('----------------');
            Debug.write('ResultElement proto:');
            Debug.inspect(google.proto.ResultElement)
            Debug.write('ResultElement members are:');
            Debug.inspect(google.proto.ResultElement.members)
            Debug.write('----------------');
            Debug.write('ResultElementArray proto:');
            Debug.inspect(google.proto.ResultElementArray)
        &lt;/method&gt;

        &lt;method event="onerror" args="error"&gt;
            debug.write('error:', error);
        &lt;/method&gt;
    &lt;/soap&gt;

&lt;/canvas&gt;
</example>

<p>The XML schema in the WSDL for Google looks like:</p>

<example extract="false">
&lt;definitions name="GoogleSearch"
             targetNamespace="urn:GoogleSearch"
             xmlns:typens="urn:GoogleSearch"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
             xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"&gt;

  &lt;types&gt;
    &lt;xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" 
                targetNamespace="urn:GoogleSearch"&gt;
            
      &lt;!-- This is represented as an object prototype with 11 members in the
              client. --&gt;
      &lt;xsd:complexType name="GoogleSearchResult"&gt;
        &lt;xsd:all&gt;
          &lt;xsd:element name="documentFiltering" type="xsd:boolean"/&gt;
          &lt;xsd:element name="searchComments" type="xsd:string"/&gt;
          &lt;xsd:element name="estimatedTotalResultsCount"  type="xsd:int"/&gt;
          &lt;xsd:element name="estimateIsExact" type="xsd:boolean"/&gt;
          &lt;xsd:element name="resultElements" type="typens:ResultElementArray"/&gt;
          &lt;xsd:element name="searchQuery" type="xsd:string"/&gt;
          &lt;xsd:element name="startIndex" type="xsd:int"/&gt;
          &lt;xsd:element name="endIndex" type="xsd:int"/&gt;
          &lt;xsd:element name="searchTips" type="xsd:string"/&gt;
          &lt;xsd:element name="directoryCategories" type="typens:DirectoryCategoryArray"/&gt;
          &lt;xsd:element name="searchTime" type="xsd:double"/&gt;
        &lt;/xsd:all&gt;
      &lt;/xsd:complexType&gt;

      &lt;!-- This will be represented as an object prototype with 9 members in
              the client. --&gt;
      &lt;xsd:complexType name="ResultElement"&gt;
        &lt;xsd:all&gt;
          &lt;xsd:element name="summary" type="xsd:string"/&gt;
          &lt;xsd:element name="URL" type="xsd:string"/&gt;
          &lt;xsd:element name="snippet" type="xsd:string"/&gt;
          &lt;xsd:element name="title" type="xsd:string"/&gt;
          &lt;xsd:element name="cachedSize" type="xsd:string"/&gt;
          &lt;xsd:element name="relatedInformationPresent" type="xsd:boolean"/&gt;
          &lt;xsd:element name="hostName" type="xsd:string"/&gt;
          &lt;xsd:element name="directoryCategory" type="typens:DirectoryCategory"/&gt;
          &lt;xsd:element name="directoryTitle" type="xsd:string"/&gt;
        &lt;/xsd:all&gt;
      &lt;/xsd:complexType&gt;

      &lt;!-- This is represented as an array prototype in the client. --&gt;
      &lt;xsd:complexType name="ResultElementArray"&gt;
        &lt;xsd:complexContent&gt;
          &lt;xsd:restriction base="soapenc:Array"&gt;
             &lt;xsd:attribute ref="soapenc:arrayType" 
                             wsdl:arrayType="typens:ResultElement[]"/&gt;
          &lt;/xsd:restriction&gt;
        &lt;/xsd:complexContent&gt;
      &lt;/xsd:complexType&gt;

      &lt;!-- This will be reprsented as an array prototype. --&gt;
      &lt;xsd:complexType name="DirectoryCategoryArray"&gt;
        &lt;xsd:complexContent&gt;
          &lt;xsd:restriction base="soapenc:Array"&gt;
             &lt;xsd:attribute ref="soapenc:arrayType"
                             wsdl:arrayType="typens:DirectoryCategory[]"/&gt;
          &lt;/xsd:restriction&gt;
        &lt;/xsd:complexContent&gt;
      &lt;/xsd:complexType&gt;

      &lt;!-- This will be reprsented as an object prototype with 2 members. --&gt;
      &lt;xsd:complexType name="DirectoryCategory"&gt;
        &lt;xsd:all&gt;
          &lt;xsd:element name="fullViewableName" type="xsd:string"/&gt;
          &lt;xsd:element name="specialEncoding" type="xsd:string"/&gt;
        &lt;/xsd:all&gt;
      &lt;/xsd:complexType&gt;

    &lt;/xsd:schema&gt;    
  &lt;/types&gt;

  &lt;!-- rest of WSDL --&gt;

&lt;/definitions&gt;
</example>


<h3>Type Mapping</h3>

<h4>Type mapping of parameters from JavaScript to SOAP encoding</h4>

<p>Parameters passed into a SOAP function from a Laszlo application will
automatically be typed according to the XML schema description in the WSDL. For
example, if a function foo() expects an integer parameter, the function can be
invoked either like foo(1) or foo('1'). When foo is invoked(), the SOAP message
sent is serialized appropriately with the correct encoding type.</p>

<h4>Type mapping of SOAP to JavaScript return types</h4>

<p>
Javascript is a loosely-typed language and may not support all the types used by the originating service.  Therefore the OpenLaszlo soap service must perform a mapping.  Here are the values used:
</p>
<table border="1">
<tr><th>SOAP types</th>
    <th>JavaScript function stub return types</th></tr>

<tr><td><b>XSD types</b></td></tr>
<tr><td>xsd:anySimpleType</td><td>String</td></tr>
<tr><td>xsd:string</td><td>String</td></tr>
<tr><td>xsd:boolean</td><td>Boolean</td></tr>
<tr><td>xsd:double</td><td>Number+</td></tr>
<tr><td>xsd:float</td><td>Number+</td></tr>
<tr><td>xsd:int</td><td>Number+</td></tr>
<tr><td>xsd:integer</td><td>Number+</td></tr>
<tr><td>xsd:long</td><td>Number+</td></tr>
<tr><td>xsd:short</td><td>Number+</td></tr>
<tr><td>xsd:byte</td><td>Number+</td></tr>

<tr><td><b>SOAP-ENC types</b></td></tr>
<tr><td>soapenc:string</td><td>String</td></tr>
<tr><td>soapenc:boolean</td><td>Boolean</td></tr>
<tr><td>soapenc:double</td><td>Number+</td></tr>
<tr><td>soapenc:float</td><td>Number+</td></tr>
<tr><td>soapenc:int</td><td>Number+</td></tr>
<tr><td>soapenc:long</td><td>Number+</td></tr>
<tr><td>soapenc:short</td><td>Number+</td></tr>
<tr><td>soapenc:byte</td><td>Number+</td></tr>
<tr><td>soapenc:Array</td><td>Array</td></tr>

<tr><td><b>Other types</b></td></tr>
<tr><td>complex types</td><td>Object (based on SOAP object proto prototype)</td></tr>
</table>
<h4>Numbers</h4>
<p>
In JavaScript all numbers are floating-point numbers. JavaScript uses the standard 8 byte IEEE floating-point numeric format, which
means the range is from:</p>
<pre>

+/- 1.7976931348623157x10^308 - very large, and +/- 5x10^-324 - very small.
</pre>
<p>
As JavaScript uses floating-point numbers the accuracy is only assured for
integers between: -9,007,199,254,740,992 (-2^53) and 9,007,199,254,740,992
(2^53)
</p>
<h4>Unsupported return types</h4>
<p>OpenLaszlo SOAP doesn't currently support the following return types:</p>

<ul>
    <li>xsd:QName</li>
    <li>xsd:anyType</li>
    <li>xsd:date</li>
    <li>xsd:time</li>
    <li>xsd:gYearMonth</li>
    <li>xsd:gYear</li>
    <li>xsd:gMonth</li>
    <li>xsd:gDay</li>
    <li>xsd:gMonthDay</li>
    <li>xsd:token</li>
    <li>xsd:normalizedString</li>
    <li>xsd:unsignedLong</li>
    <li>xsd:unsignedInt</li>
    <li>xsd:unsignedShort</li>
    <li>xsd:unsignedByte</li>
    <li>xsd:nonNegativeInteger</li>
    <li>xsd:negativeInteger</li>
    <li>xsd:positiveInteger</li>
    <li>xsd:nonPositiveInteger</li>
    <li>xsd:Name</li>
    <li>xsd:NCName</li>
    <li>xsd:ID</li>
    <li>xsd:language</li>
    <li>xsd:NMTOKEN</li>
    <li>xsd:NMTOKENS</li>
    <li>xsd:NOTATION</li>
    <li>xsd:ENTITY</li>
    <li>xsd:ENTITIES</li>
    <li>xsd:IDREF</li>
    <li>xsd:IDREFS</li>
    <li>xsd:duration</li>
    <li>xsd:anyURI</li>
    <li>xsd:schema</li>
    <li>soapenc:Map</li>
    <li>soapenc:Element</li>
    <li>soapenc:Document</li>
    <li>soapenc:Vector</li>
</ul>
<h2>SOAP headers</h2>

<p>SOAP headers are the metadata passed with SOAP messages. During transmission,
intermerdiaries may process headers while leaving the SOAP body unchanged. For
example, a security service could provide authentication this way.  Though SOAP
headers are largely unused today, this may change as more secured SOAP services
are implemented.</p>

<h3>Request headers</h3>

<p>To set SOAP request headers with each outgoing message, set the
requestheaders attribute with an XML string (a root node is not required).</p>

<example title="SOAP request headers" extract="false">
&lt;soap name="calendar" wsdl="http://www.mycompany.com/Calendar.wsdl"&gt;  
    &lt;attribute name="requestheaders" value='&lt;usr&gt;name&lt;/usr&gt;&lt;pwd&gt;secret&lt;/pwd&gt;' /&gt;  
&lt;!-- ... --&gt; 
&lt;/soap&gt;  
</example>

<p>You can use the <method>onload</method> event to trigger the setting of a
header value.</p>

<example extract="false" title="Setting SOAP request headers in a method">
&lt;soap name="calendar" wsdl="http://www.mycompany.com/Calendar.wsdl"&gt; 
    &lt;method event="onload"&gt;  
    &lt;![CDATA[
       this.requestheaders = '&lt;usr&gt;name&lt;/usr&gt;' +  '&lt;pwd&gt;secret&lt;/pwd&gt;'
    ]]&gt; 
    &lt;/method&gt;  
    &lt;!-- ... --&gt; 
&lt;/soap&gt; 
</example>

<p>To remove request headers, simply clear the requestheaders attribute by
resetting its value, for example, <code>requestheaders=''.</code></p>

<h3>Response headers</h3>

<p>To access response headers from a SOAP response, set the responseheaders
attribute with a dataset.</p>

<example title="SOAP response headers" extract="false">
&lt;canvas&gt;

    &lt;dataset name="resds" /&gt;

    &lt;soap name="lq" wsdl="file:ReservationService.wsdl" requestheaders="..." 
          responseheaders="resds"&gt;
          ...
        &lt;method event="ondata"&gt;
            // print out response headers whenever we get data.
            Debug.write(resds.serialize());
        &lt;/method&gt;

    &lt;/soap&gt;

    &lt;!-- ... --&gt;
&lt;/canvas&gt;
</example>
<h2>Handling of overloaded methods on the service</h2>
<p>
The SOAP specification allows overloaded operations, that is, methods that contain the same name but have different parameters. This creates a mismatch with Javascript, which does not allow overloaded methods. Here is how we handle this.</p>
<p>
If there are overloaded SOAP operations the OpenLaslo Server returns "mangled" names for those operations based on the request and response parameters. For example, if there are SOAP operations that are defined like the following in the WSDL:
</p>
<pre>

  getFoo(request1, response1)
  getFoo(request2, response2)
  getFoo(request3, response3)
</pre>
<p>
the SOAP object in the LZX application will contain the following methods:
</p>
<pre>
  getFoo()
  getFoo_request2_response2()
  getFoo_request3_response3()
</pre>
<p>
The reason why these methods need to be mangeld in LZX is because there's no way to have more than instance of <method>getFoo</method> in Javascript so we do this on the client to differentiate the three method calls.
</p>
<h2>Limitations on OpenLaszlo SOAP implementation</h2>
<p>
The OpenLaszlo implementation of the SOAP specification has the following deviations:
</p>
<ul>
    <li>Only WSDL 1.1 documents are suppported. WSDL 2.0 documents are not
    supported.</li>
    <li>The WSDL &lt;import&gt; tag is not supported.</li>
    <li>SOAP 1.1 partially transmitted arrays and sparse arays are not
    supported.</li>
    <li>Multidimensional arrays are not supported.</li>
    <li>SOAP attachments are not supported.</li>
    <li>Multireferences are not supported. Items that are referenced more than
    once are created as different instances.</li>
</ul>


<h2>References</h2>

<ul>
    <li>
    <a href="http://www.w3.org/TR/2000/NOTE-SOAP-20000508/">
        SOAP 1.1 (W3C Note)
    </a>
    </li>

    <li>
    <a href="http://www.w3.org/TR/soap12-part0/">
        SOAP 1.2 Part 0: Primer (W3C Recommendation)
    </a>
    </li>

    <li>
    <a href="http://www.w3.org/TR/wsdl">
        WSDL 1.1 (W3C Note)
    </a>
    </li>

    <li>
    <a href="http://www.w3.org/TR/wsdl20/">
        WSDL 2.0 Part 1: Core Language (W3C Working Draft)
    </a>
    </li>

    <li>
    <a href="http://www.ws-i.org/Profiles/BasicProfile-1.0-2004-04-16.html">
        Basic Profile Version 1.0 (WS-I Final Material)
    </a>
    </li>

    <li>
    <a href="http://www-106.ibm.com/developerworks/webservices/library/ws-whichwsdl/">
        Which style of WSDL should I use? (IBM developer works)
    </a>
    </li>

    <li>
    <a href="http://www.w3.org/TR/2001/REC-xmlschema-0-20010502/">
        XML Schema Part 0: Primer (W3C Recommendation)
    </a>
    </li>

    <li>
    <a href="http://www.w3.org/TR/REC-xml/">
    Extensible Markup Language (XML) 1.0 (W3C Recommendation)
    </a>
    </li>

    <li>
    <a href="http://www.w3.org/TR/1999/REC-xml-names-19990114/">
        Namespaces in XML
    </a>
    </li>

    <li>WSDLs used in this document

        <ul>
            <li><a
            href="http://soap.amazon.com/schemas3/AmazonWebServices.wsdl">Amazon</a>:
            RPC style operation parameters are complex data structures</li>
            <li><a href="http://api.google.com/GoogleSearch.wsdl">Google</a>:
            RPC style operation parameters are simple types</li>
            <li><a
            href="http://www.dotnetjunkies.com/quickstart/aspplus/samples/services/MathService/VB/MathService.asmx?WSDL">.NET
            MathService: Document style operations</a></li>
        </ul>
    
    </li>
</ul>


</body>
</html>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2001-2004 Laszlo Systems, Inc.  All Rights Reserved.              *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
